package com.epalmpay.service.bonus.impl;

import com.epalmpay.exception.ApplicationException;
import com.epalmpay.entity.*;
import com.epalmpay.enumdef.ActivityEnum;
import com.epalmpay.enumdef.CommonEnum;
import com.epalmpay.mapper.*;
import com.epalmpay.service.bonus.IBonusService;
import com.epalmpay.util.AmountUtils;
import com.epalmpay.util.DateUtil;
import com.epalmpay.util.Logger;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by gwn on 2017/9/12.
 */
@Service("bonusService")
public class BonusServiceImpl implements IBonusService {

    protected Logger logger = Logger.getLogger(this.getClass());

    @Resource
    private BonusAdjustBatchMapper bonusAdjustBatchMapper;
    @Resource
    private MemberMapper memberMapper;
    @Resource
    private BonusSendLogMapper bonusSendLogMapper;

    @Resource
    private BonusVerifyRuleMapper bonusVerifyRuleMapper;
    @Resource
    private BonusVerifyLogMapper bonusVerifyLogMapper;

    @Resource
    private BonusVerifyShopMapper bonusVerifyShopMapper;
    @Resource
    private BonusSendShopMapper bonusSendShopMapper;

    @Resource
    private BonusSendRuleMapper bonusSendRuleMapper;


    @Resource(name="transactionManager")
    private DataSourceTransactionManager transactionManager;

    /***
     * 给单个会员发积分(手动事物)
     *   说明：(1)消费送延时入账，签到、升级送、手动增加(审核完成)直接入账
     * @return
     *     int:插入数量
     *     -1:表示不在时间范围之内，发积分失败
     * @throws Exception
     */
    public int sendOneMemberBonus(BonusSendLog bonusSendLog) throws Exception{
        //DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        //def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别，开启新事务
        //TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态

        int result = 0;

        try {
            Date date = new Date();
            bonusSendLog.setGmtCreate(date);
            bonusSendLog.setGmtModified(date);

            int bonusAccountedTime = 0;//入账时间临时变量

            switch (ActivityEnum.BonusSendType.fromType(bonusSendLog.getSendType())){
                case ConsumeSend:
                    BonusSendRule rule = bonusSendRuleMapper.selectDefaultOrByShopId(bonusSendLog.getGroupId(),bonusSendLog.getShopId());
                    if(rule != null){
                        //时间段验证
                        if(rule.getSendTimeType() == ActivityEnum.TimeRangeType.TimeRange.getType()){
                            Boolean isRange = Boolean.FALSE;
                            if(rule.getSendTimeFrom1() != null &&
                                    (date.compareTo(rule.getSendTimeFrom1()) >0 && date.compareTo(rule.getSendTimeTo1()) < 0 ))
                                isRange = Boolean.TRUE;
                            else if(rule.getSendTimeFrom2() != null &&
                                    (date.compareTo(rule.getSendTimeFrom2()) >0 && date.compareTo(rule.getSendTimeTo2()) < 0 ))
                                isRange = Boolean.TRUE;
                            else if(rule.getSendTimeFrom3() != null &&
                                    (date.compareTo(rule.getSendTimeFrom3()) >0 && date.compareTo(rule.getSendTimeTo3()) < 0 ))
                                isRange = Boolean.TRUE;
                            if(!isRange) {
                                //transactionManager.rollback(status);
                                return -1;
                            }
                        }
                        //单笔超限
                        if(rule.getSendSingleMax() != 0 && bonusSendLog.getAdjustAmount() > rule.getSendSingleMax()) {
                            bonusSendLog.setAdjustStatus(ActivityEnum.BonusSendStatus.Freezing.getType());
                            bonusSendLog.setIsFlag(CommonEnum.YesOrNo.Yes.getType());
                            //更新会员冻结积分
                            result = memberMapper.updateBonusFreezeById(bonusSendLog.getMemberId(),bonusSendLog.getAdjustAmount());
                            break;
                        }
                        //取得会员当天记录
                        BonusSendRule memberDayDate = bonusSendLogMapper.selectDaySumAndCountByMemberId(bonusSendLog.getMemberId());
                        if(memberDayDate != null){
                            if(rule.getSendDayMax() != 0 && memberDayDate.getSendDayMax() > rule.getSendDayMax()) {
                                bonusSendLog.setAdjustStatus(ActivityEnum.BonusSendStatus.Freezing.getType());
                                bonusSendLog.setIsFlag(CommonEnum.YesOrNo.Yes.getType());
                                //更新会员冻结积分
                                result = memberMapper.updateBonusFreezeById(bonusSendLog.getMemberId(),bonusSendLog.getAdjustAmount());
                            }
                            else if(rule.getSendDayCount() != 0 && memberDayDate.getSendDayCount() > rule.getSendDayCount()) {
                                bonusSendLog.setAdjustStatus(ActivityEnum.BonusSendStatus.Freezing.getType());
                                bonusSendLog.setIsFlag(CommonEnum.YesOrNo.Yes.getType());
                                //更新会员冻结积分
                                result = memberMapper.updateBonusFreezeById(bonusSendLog.getMemberId(),bonusSendLog.getAdjustAmount());
                            }
                        }
                        bonusAccountedTime = rule.getSendAccountedTime();
                    }
                    break;
                case Sign:
                case UpdateSend:
                //手动增加功能:可以增加负数表示积分减少
                case ManualAdd:
                case routineActivityBirthday:
                case routineActivityTime:
                case routineActivityCycleLife:
                case routineActivityRegister:
                case routineActivitySign:
                    //更新会员积分
                    result = memberMapper.updateMemberBonusById(bonusSendLog.getMemberId(),bonusSendLog.getAdjustAmount());
                    //更新门店赠送积分
                    if(bonusSendLog.getShopId() !=null ) {
                        result = bonusSendShopMapper.insertShopSendBonus(bonusSendLog.getShopId(), AmountUtils.integerAbs(bonusSendLog.getAdjustAmount()));
                    }
                    break;
                default:
                    break;
            }
            bonusSendLog.setAccountingTime(DateUtil.getTimeByHour(bonusAccountedTime));
            result = bonusSendLogMapper.insert(bonusSendLog);
            //transactionManager.commit(status);

        }catch (Exception e) {
            //transactionManager.rollback(status);
            logger.error("commit", e);
            e.printStackTrace();
            throw e;
        }
        return result;
    }

    //计划任务自动积分入账
    public int insertMemberBonus() throws Exception{
        int result = 0;

        //插入会员积分
        result = memberMapper.insertMemberBonus();
        //批量插入门店发送积分
        result = bonusSendShopMapper.insertBatchShopSendBonus();
        //批量入账
        result = bonusSendLogMapper.updateAccountedStatus();

        return result;
    }

    /***
     * 给单个会员积分进行核销(手动事物)
     * @return
     *     int:插入数量
     *     -1:表示不在时间范围之内，核销积分失败-=
     *     -2:表示低于最低核销积分数，不使用积分
     *     -4:表示超过当天核销积分总量
     *     -5:表示超过当天核销积分总笔数
     * @throws Exception
     */
    public int verifyOneMemberBonus(BonusVerifyLog bonusVerifyLog,Integer payAmount) throws Exception{

        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 事物隔离级别，开启新事务
        TransactionStatus status = transactionManager.getTransaction(def); // 获得事务状态

        int result = 0;

        try {
            Date date = new Date();
            bonusVerifyLog.setGmtCreate(date);
            bonusVerifyLog.setGmtModified(date);

            //取得会员积分
            Member member = memberMapper.queryBonusAmount(bonusVerifyLog.getMemberId());
            if(member == null)
                return -6;

            member.setBonusAmount(member.getBonusAmount()==null?0:member.getBonusAmount());

            switch (ActivityEnum.BonusVerityType.fromType(bonusVerifyLog.getVerifyType())){
                case Consume:
                    //如果超过会员积分，取现有积分为最大值
                    if(AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()) > member.getBonusAmount())
                        bonusVerifyLog.setAdjustAmount(-1 * member.getBonusAmount());

                    BonusVerifyRule rule = bonusVerifyRuleMapper.selectDefaultOrByShopId(bonusVerifyLog.getGroupId(),bonusVerifyLog.getShopId());
                    if(rule != null){
                        //时间段验证
                        if(rule.getVerifyTimeType() == ActivityEnum.TimeRangeType.TimeRange.getType()){
                            Boolean isRange = Boolean.FALSE;
                            if(rule.getVerifyTimeFrom1() != null &&
                                    (date.compareTo(rule.getVerifyTimeFrom1()) >0 && date.compareTo(rule.getVerifyTimeTo1()) < 0 ))
                                isRange = Boolean.TRUE;
                            else if(rule.getVerifyTimeFrom2() != null &&
                                    (date.compareTo(rule.getVerifyTimeFrom2()) >0 && date.compareTo(rule.getVerifyTimeTo2()) < 0 ))
                                isRange = Boolean.TRUE;
                            else if(rule.getVerifyTimeFrom3() != null &&
                                    (date.compareTo(rule.getVerifyTimeFrom3()) >0 && date.compareTo(rule.getVerifyTimeTo3()) < 0 ))
                                isRange = Boolean.TRUE;
                            if(!isRange) {
                                transactionManager.rollback(status);
                                return -1;
                            }
                        }
                        //单笔最低判断
                        if(rule.getVerifySingleMinType() == ActivityEnum.BackMoneyMode.FiexedAmount.getType() ){
                            if(AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()) < rule.getVerifySingleMin()){
                                transactionManager.rollback(status);
                                return -2;
                            }
                        }else if(rule.getVerifySingleMinType() == ActivityEnum.BackMoneyMode.Percentage.getType() ){
                            Integer bonusAount = 0;
                            bonusAount = payAmount * rule.getVerifySingleMin() * rule.getVerifyRate()/(100*100);
                            if(AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()) < bonusAount){
                                transactionManager.rollback(status);
                                return -2;
                            }
                        }
                        //单笔最多判断(超过最多按)
                        if(rule.getVerifySingleMaxType() == ActivityEnum.BackMoneyMode.FiexedAmount.getType() ){
                            if(AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()) > rule.getVerifySingleMax()){
                                bonusVerifyLog.setAdjustAmount(-1 * rule.getVerifySingleMax());
                                //transactionManager.rollback(status);
                                //return -3;
                            }
                        }else if(rule.getVerifySingleMaxType() == ActivityEnum.BackMoneyMode.Percentage.getType() ){
                            Integer bonusAount = 0;
                            bonusAount = payAmount * rule.getVerifySingleMax() * rule.getVerifyRate()/(100*100);
                            if(AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()) > bonusAount){
                                bonusVerifyLog.setAdjustAmount(-1 * bonusAount);
                                //transactionManager.rollback(status);
                                //return -3;
                            }
                        }

                        //取得会员当天记录
                        BonusVerifyRule memberDayDate = bonusVerifyLogMapper.selectDaySumAndCountByMemberId(bonusVerifyLog.getMemberId());
                        if(memberDayDate != null){
                            if(AmountUtils.integerAbs(memberDayDate.getVerifyDaySum()) > rule.getVerifyDaySum()) {
                                transactionManager.rollback(status);
                                return -4;
                            }
                            else if(memberDayDate.getVerifyDayCount() > rule.getVerifyDayCount()){
                                transactionManager.rollback(status);
                                return -5;
                            }
                        }
                        //计算核销积分的对应金额(分)
                        if(rule.getVerifyRate() != null && rule.getVerifyRate() != 0) {
                            bonusVerifyLog.setAdjustValue(bonusVerifyLog.getAdjustAmount() * 100 / rule.getVerifyRate());
                        }
                    }
                    //更新会员积分
                    result = memberMapper.updateMemberBonusById(bonusVerifyLog.getMemberId(),bonusVerifyLog.getAdjustAmount());
                    //更新门店核销积分
                    result = bonusVerifyShopMapper.insertShopVerifyBonus(bonusVerifyLog.getGroupId(),
                            bonusVerifyLog.getShopId(),AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()));
                    break;
                case TradeCancel://交易撤销
                    result = memberMapper.updateMemberBonusById(bonusVerifyLog.getMemberId(),bonusVerifyLog.getAdjustAmount());
                    //更新门店核销积分
                    result = bonusVerifyShopMapper.insertShopVerifyBonus(bonusVerifyLog.getGroupId(),
                            bonusVerifyLog.getShopId(),-1 * AmountUtils.integerAbs(bonusVerifyLog.getAdjustAmount()));
                    break;
                case Exchange:
                    result = memberMapper.updateMemberBonusById(bonusVerifyLog.getMemberId(),bonusVerifyLog.getAdjustAmount());
                    break;
                default:
                    break;
            }
            result = bonusVerifyLogMapper.insert(bonusVerifyLog);
            transactionManager.commit(status);

        }catch (Exception e) {
            transactionManager.rollback(status);
            logger.error("commit", e);
            e.printStackTrace();
            throw e;
        }
        return result;
    }

    /***
     * 获取会员可用积分
     * @param memberId
     * @param shopId,交易门店,可空
     * @param payAmount,交易金额,可空
     * @return maxAvaiableBonus最大可用积分,valueAmount等值金额,verifyRate积分核销比例,minBonus最低积分点数
     * @throws Exception
     */
    public Map<String, Object> getMemberAvaiableBonus(Long memberId,Long shopId,Integer payAmount) throws Exception{
        Map<String, Object> map = new HashMap<String, Object>();

        payAmount = payAmount==null?0:payAmount;

        //取得会员积分
        Member member = memberMapper.queryBonusAmount(memberId);
        if(member == null)
            throw new ApplicationException("会员id:"+memberId+"不存在!");

        Date date = new Date();

        Integer maxAvaiableBonus = 0;
        Integer valueAmount = 0;
        Integer verifyRate = 0;
        Integer minBonus = 0;

        BonusVerifyRule rule = bonusVerifyRuleMapper.selectDefaultOrByShopId(member.getGroupId(),shopId);
        if(rule == null)
            throw new ApplicationException("请设置积分核销规则!");


        //取得会员当天记录
        BonusVerifyRule memberDayDate = bonusVerifyLogMapper.selectDaySumAndCountByMemberId(memberId);
        if (memberDayDate != null) {
            if (AmountUtils.integerAbs(memberDayDate.getVerifyDaySum()) >= rule.getVerifyDaySum()) {
                throw new ApplicationException("超过当天核销总数!");
            }
            if (memberDayDate.getVerifyDayCount() >= rule.getVerifyDayCount()) {
                throw new ApplicationException("超过当天核销总笔数!");
            }
        }

        verifyRate = rule.getVerifyRate();

        //单笔最低判断
        if (rule.getVerifySingleMinType() == ActivityEnum.BackMoneyMode.FiexedAmount.getType()) {
            minBonus = rule.getVerifySingleMin();
        } else if (rule.getVerifySingleMinType() == ActivityEnum.BackMoneyMode.Percentage.getType()) {
            minBonus = payAmount * rule.getVerifySingleMin() * rule.getVerifyRate() / (100 * 100);
        }
        //单笔最多判断(超过最多按)
        if (rule.getVerifySingleMaxType() == ActivityEnum.BackMoneyMode.FiexedAmount.getType()) {
            if (member.getBonusAmount() > rule.getVerifySingleMax()) {
                maxAvaiableBonus = rule.getVerifySingleMax();
            } else {
                maxAvaiableBonus = member.getBonusAmount();
            }

        } else if (rule.getVerifySingleMaxType() == ActivityEnum.BackMoneyMode.Percentage.getType()) {
            Integer bonusAount = 0;
            bonusAount = payAmount * rule.getVerifySingleMax() * rule.getVerifyRate() / (100 * 100);
            if (member.getBonusAmount() > bonusAount) {
                maxAvaiableBonus = bonusAount;
            } else {
                maxAvaiableBonus = member.getBonusAmount();
            }
        }

        //计算核销积分的对应金额(分)
        if (rule.getVerifyRate() != null && rule.getVerifyRate() != 0) {
            valueAmount = maxAvaiableBonus * 100 / rule.getVerifyRate();
        }

        map.put("maxAvaiableBonus",maxAvaiableBonus);
        map.put("valueAmount",valueAmount);
        map.put("verifyRate",verifyRate);
        map.put("minBonus",minBonus);
        return map;
    }

}
